package com.daxia.ogmall.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.daxia.ogmall.common.CompanyStatus;
import com.daxia.ogmall.common.FactoryInfoStatus;
import com.daxia.ogmall.common.PayBizType;
import com.daxia.ogmall.common.PayStatus;
import com.daxia.ogmall.common.SmsSendType;
import com.daxia.ogmall.dao.PayDAO;
import com.daxia.ogmall.dto.CompanyDTO;
import com.daxia.ogmall.dto.FactoryInfoDTO;
import com.daxia.ogmall.dto.PayDTO;
import com.daxia.ogmall.model.Brand;
import com.daxia.ogmall.model.FactoryInfo;
import com.daxia.ogmall.model.Order;
import com.daxia.ogmall.model.OrderItem;
import com.daxia.ogmall.model.Pay;
import com.daxia.ogmall.model.User;
import com.daxia.ogmall.support.Page;
import com.daxia.ogmall.util.BeanMapper;
import com.daxia.ogmall.util.SmsService;

@Service
public class PayService {
	
	@Autowired
	private PayDAO payDAO;

	@Autowired
	private OrderService orderService;
	
	@Autowired
	private ProductService productService;
	
	@Autowired
	private UserService userService;
	
	@Autowired
	private FactoryInfoService factoryInfoService;
	
	@Autowired
	private CompanyService companyService;
	
	public List<PayDTO> find(PayDTO query, Page page) {
		List<Pay> models = payDAO.find(query, page);
		List<PayDTO> dtos = toDTOs(models);
		return dtos;
	}
	
	public List<PayDTO> findAll() {
		return this.find(new PayDTO(), null);
	}
	
	public List<PayDTO> find(int count) {
		Page page = new Page();
		page.setPage(1);
		page.setPageSize(count);
		return this.find(new PayDTO(), page);
	}
	
	public Long create(PayDTO dto) {
		Pay model = new Pay();
		toModel(model, dto);
		return payDAO.create(model);
	}
	
	public PayDTO load(Long id) {
	    Pay model = payDAO.load(id);
	    return toDTO(model);
    }

	public void updateAllFields(PayDTO dto) {
		Pay model = payDAO.load(dto.getId());
		toModel(model, dto);
		payDAO.update(model);
    }

	public void deleteByIds(Long[] ids) {
		if (ids != null) {
			for (Long id : ids) {
				payDAO.deleteById(id);
			}
		}
    }
	
	public void deleteById(Long id) {
		this.deleteByIds(new Long[] {id});
	}

	public PayDTO findOne(PayDTO query) {
		Pay model = payDAO.findOne(query);
		return toDTO(model);
	}
	
	private List<PayDTO> toDTOs(List<Pay> models) {
		if (CollectionUtils.isEmpty(models)) {
			return new ArrayList<PayDTO>(0);
		}
		List<PayDTO> dtos = new ArrayList<PayDTO>(models.size());
		for (Pay model : models) {
	        PayDTO dto = toDTO(model);
	        dtos.add(dto);
        }
	    return dtos;
    }
    
    private PayDTO toDTO(Pay model) {
		if (model == null) {
			return null;
		}
		PayDTO dto = BeanMapper.map(model, PayDTO.class);
		
		return dto;
	}
	
	private void toModel(Pay model, PayDTO dto) {
		BeanMapper.copy(dto, model);
    }
	
	@SuppressWarnings("unused")
	private List<Pay> toModels(List<PayDTO> dtos) {
		if (CollectionUtils.isEmpty(dtos)) {
			return new ArrayList<Pay>(0);
		}
		List<Pay> models = new ArrayList<Pay>(dtos.size());
		for (PayDTO dto : dtos) {
	        Pay model = new Pay();
	        toModel(model, dto);
	        models.add(model);
        }
		return models;
	}

	public PayDTO findByPaymentNo(String paymentNo) {
		PayDTO query = new PayDTO();
		query.setPaymentNo(paymentNo);
		return this.findOne(query);
	}
	public PayDTO findByOrderNo(String orderNo) {
		PayDTO query = new PayDTO();
		query.setOrderNo(orderNo);
		return this.findOne(query);
	}

	@Transactional
	public void onSuccess(Long payId) throws Exception {
		this.onSuccess(this.load(payId));
	}
	
	@Transactional
	public void onSuccess(String paymentNo) throws Exception { 
		this.onSuccess(this.findByPaymentNo(paymentNo));
	}
	
	@Transactional
	public void wxPaySuccess(String paymentNo) throws Exception {   
		PayDTO p = new PayDTO();
        p = findByPaymentNo(paymentNo);
        updatePayStatus(p.getId(), PayStatus.Payed.getValue());
        p.setStatus(PayStatus.Payed.getValue());
        onSuccess(p);
	}
	
	@Transactional
	public void onSuccess(PayDTO p) throws Exception {    //2016-11-15增加发送短信     
		if (p.getStatus() == PayStatus.Payed.getValue()) {
			if (p.getBizType() == PayBizType.FactoryRegister.getValue()) {    //工厂注册更改状态
				User user = p.getUser();
				FactoryInfoDTO queryFactory = new FactoryInfoDTO();
				queryFactory.setUser(user);
				FactoryInfoDTO factory = factoryInfoService.findFactoryByUserId(user.getId());
				factoryInfoService.updateFactoryStatus(factory.getId(), FactoryInfoStatus.Payed.getValue());
			} else if(p.getBizType() == PayBizType.CompanyRegister.getValue()) {   //装修公司注册更改状态
				User user = p.getUser();
				CompanyDTO company = new CompanyDTO();
				company.setUser(user);
				company = companyService.findCompanyByUserId(user.getId());
				companyService.updateCompanyStatuS(company.getId(), CompanyStatus.Payed.getValue());
				SmsService.sendWithTemplate(user.getMobile(), SmsSendType.CompanyPayed.getValue(), new HashMap<String,Object>());
			} else {
				if (p.getOrder() != null) { // 1 个订单的 
					processOrderSuccess(p.getOrder(), p.getAmount());
					goSendSmsForOrder(p.getUser(),p.getOrder());
				} else if (StringUtils.isNotBlank(p.getOrderIds())) {
					for (String idString : p.getOrderIds().split(",")) {
						Order order = orderService.load(Long.valueOf(idString));
						processOrderSuccess(order, p.getAmount());
						goSendSmsForOrder(p.getUser(),order);
					}
				}
			}
		}
	}
	
	public void goSendSmsForOrder(User user,Order order) throws Exception {   //根据用户和支付记录发送短信信息
		String orderNo = order.getOrderNo();  
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("orderNo", orderNo);
		SmsService.sendWithTemplate(user.getMobile(), SmsSendType.UserPaySuccess.getValue(), map);   //给用户发送成功支付
		SmsService.sendWithTemplate(SmsService.adminMobile, SmsSendType.PaySuccessFactory.getValue(), map);    //给管理员发送支付通知
		//因为是同一个工厂的（就是商品的品牌的所属工厂）的商品，只会出现在一个订单内，所以只要拿出第一个商品单就能得到对应的工厂号码
		OrderItem firstItem = order.getOrderItems().get(0);
		Brand brand = firstItem.getProduct().getBrand();
		if(brand != null && brand.getFactoryInfo() != null) {      //给工厂用户发送支付通知
			FactoryInfo factoryInfo = brand.getFactoryInfo();
			String mobile = factoryInfo.getUser().getMobile();
			if(StringUtils.isNotBlank(mobile)) {
				SmsService.sendWithTemplate(mobile, SmsSendType.PaySuccessFactory.getValue(),map);
			}
		}
	}

	private void processOrderSuccess(Order order, Integer amount) {
		Double actualPayAmount = Double.parseDouble(amount + "")/100;
		Long orderId = order.getId();
		List<Long> addProductIds = new Vector<Long>();
		for(OrderItem item : order.getOrderItems()) {
			addProductIds.add(item.getProduct().getId());
		}
		productService.updateTotalSold(addProductIds);
		orderService.onSuccess(orderId,new BigDecimal(actualPayAmount));
	}

	/**
	 * 支付失败了
	 * @param payId
	 * @param msg
	 */
	@Transactional
	public void onFailed(String orderNo, String msg) {
		
	}
	
	@Transactional
	public void updatePayStatus(Long payId,Integer status) {
		payDAO.updatePayStatus(payId, status);
	}

	/**
	 * 查找装修公司的开通支付记录
	 * @param companyUserId 装修公司相关联的用户id
	 * @return
	 */
	public PayDTO findComanyPay(Long companyUserId) {
		PayDTO query = new PayDTO();
		query.setBizType(PayBizType.CompanyRegister.getValue());
		query.setUser(new User());
		query.getUser().setId(companyUserId);
		return this.findOne(query);
	}
	
}
